#include "Socket.h"
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <endian.h>
#include "util.h"

// 创建非阻塞socket
int createNonblockingSocket()
{
    int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
    if (sockfd < 0){
    }
    return sockfd;
}

int getSocketError(int sockfd)
{
  int optval;
  socklen_t optlen = static_cast<socklen_t>(sizeof optval);

  if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
  {
    return errno;
  }
  else
  {
    return optval;
  }
}

struct sockaddr* sockaddr_cast(struct sockaddr_in* addr)
{
  return static_cast<struct sockaddr*>(static_cast<void*>(addr));
}
struct sockaddr_in getLocalAddr(int sockfd)
{
  struct sockaddr_in localaddr;
  bzero(&localaddr, sizeof localaddr);
  socklen_t addrlen = static_cast<socklen_t>(sizeof localaddr);
  if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
  {
    // LOG_SYSERR << "sockets::getLocalAddr";
  }
  return localaddr;
}

struct sockaddr_in getPeerAddr(int sockfd)
{
  struct sockaddr_in peeraddr;
  bzero(&peeraddr, sizeof peeraddr);
  socklen_t addrlen = static_cast<socklen_t>(sizeof peeraddr);
  if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0)
  {
    // LOG_SYSERR << "sockets::getPeerAddr";
  }
  return peeraddr;
}

bool isSelfConnect(int sockfd)
{
  struct sockaddr_in localaddr = getLocalAddr(sockfd);
  struct sockaddr_in peeraddr = getPeerAddr(sockfd);
  return localaddr.sin_port == peeraddr.sin_port
      && localaddr.sin_addr.s_addr == peeraddr.sin_addr.s_addr;
}

std::string toIpPort(struct sockaddr_in addr)
{
  char buf[32];
  size_t size = sizeof(buf);
  ::inet_ntop(AF_INET, &addr.sin_addr, buf, static_cast<socklen_t>(size));
  size_t end = ::strlen(buf);
  uint16_t port = be16toh(addr.sin_port);
  snprintf(buf+end, size-end, ":%u", port);

  return buf;
}

std::string toIp(struct sockaddr_in addr_)
{
  char buf[32];
  ::inet_ntop(AF_INET, &addr_.sin_addr, buf, static_cast<socklen_t>(sizeof(buf)));
  return buf;
}

uint16_t toPort(struct sockaddr_in addr_)
{
  return be16toh(addr_.sin_port);
}


Socket::~Socket() {
    
    // printf("TID: %d fd: %d Socket::~Socket\n", getTid(), sockfd_);
    if (close(sockfd_) < 0) {
        printf("TID: %d Socket %d Close Error\n", getTid(), sockfd_);
    }
}

void Socket::bindAddress(int port) {
  struct sockaddr_in servAddr;
  bzero(&servAddr, sizeof(servAddr));
  servAddr.sin_family = AF_INET;
  servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servAddr.sin_port = htons(port);

  int ret = bind(sockfd_, (struct sockaddr *)&servAddr, sizeof(servAddr));
  if (ret < 0) { 
    std::cout << "bind error.. port: " << port << std::endl;
  }
}

void Socket::listening( ) {
  int ret = listen(sockfd_, SOMAXCONN);
  if (ret < 0) {
    std::cout << "listen error.." << std::endl;
  }
}

int Socket::accept() {
  struct sockaddr_in clt_adr;
  bzero(&clt_adr, sizeof(clt_adr));
  socklen_t clt_adr_sz = sizeof(clt_adr);
  int connfd = ::accept4(sockfd_, (struct sockaddr* )&clt_adr, &clt_adr_sz, SOCK_NONBLOCK | SOCK_CLOEXEC);
  if (connfd > 0) { }
  return connfd;
}


void Socket::setReuseAddr(bool on) {
    int optval = on ? 1 : 0;
    setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
}

void Socket::shutdownWrite() {
    if (shutdown(sockfd_, SHUT_WR) < 0) { }
}

void Socket::setTcpNoDelay(bool on) {
    int optval = on ? 1 : 0;
    setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof optval);
}

void Socket::setKeepAlive(bool on) {
    int optval = on ? 1 : 0;
    setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof optval);

    int keepidle = 10; // 如该连接在60秒内没有任何数据往来,则进行探测
    int keepinterval = 5; // 探测时发包的时间间隔为5 秒
    int keepcount = 2; // 探测尝试的次数。如果第1次探测包就收到响应了,则后2次的不再发。
    setsockopt(sockfd_, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle ));
    setsockopt(sockfd_, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval ));
    setsockopt(sockfd_, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount ));
}